use crate::service::model::chat_handler_model;
use crate::service::model::chat_handler_model::{Connection, Disconnect, WsRequest};
use crate::service::server::chat::ChatServer;
use actix::*;
use actix_web::rt::time::Instant;
use actix_web_actors::ws;
use std::collections::HashMap;
use std::time::Duration;

pub struct ChatSession {
    pub id: usize,
    pub info: HashMap<String, String>,
    pub hb: Instant,
    pub addr: Addr<ChatServer>,
}

impl Actor for ChatSession {
    type Context = ws::WebsocketContext<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        self.hb(ctx);
        let addr = ctx.address();
        let recipient: Recipient<chat_handler_model::Message> = addr.recipient();
        self.addr
            .send(Connection {
                id: self.id,
                info: self.info.clone(),
                addr: recipient,
            })
            .into_actor(self)
            .then(|res, act, ctx| {
                match res {
                    Ok(()) => {}
                    _ => ctx.stop(),
                }
                fut::ready(())
            })
            .wait(ctx);
    }

    fn stopping(&mut self, _ctx: &mut Self::Context) -> Running {
        println!("stopping:{}", self.id);
        self.addr.do_send(Disconnect { id: self.id });
        Running::Stop
    }
}

impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for ChatSession {
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        let msg = match msg {
            Err(_) => {
                ctx.stop();
                return;
            }
            Ok(msg) => msg,
        };

        match msg {
            ws::Message::Ping(msg) => {
                self.hb = Instant::now();
                ctx.pong(&msg);
            }
            ws::Message::Pong(msg) => {
                self.hb = Instant::now();
            }
            ws::Message::Text(text) => {
                self.addr.do_send(WsRequest { id: self.id, text });
            }
            ws::Message::Close(response) => {
                ctx.close(response);
                ctx.stop();
            }
            ws::Message::Continuation(_) => {
                ctx.stop();
            }
            ws::Message::Nop => (),
            ws::Message::Binary(_) => println!("Unexpected binary"),
        }
    }
}

/// 延迟时间
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(10);
/// 超时时间
const CLIENT_TIMEOUT: Duration = Duration::from_secs(150000);

impl ChatSession {
    fn hb(&self, ctx: &mut ws::WebsocketContext<Self>) {
        ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
            if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
                println!("超时id:{}\n state={:?}", act.id, ctx.state());
                act.addr.do_send(Disconnect { id: act.id });
                ctx.stop();
                return;
            }
            ctx.ping(b"");
        });
    }
}
